package com.monas.client.export;

import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;

/**
 * Class abstrak untuk melakukan render ke file excel 2003/2007.
 * 
 * @author 'Eko Wahyudi'
 * 
 */
public abstract class AbstractExcel extends Renderer {

	protected Workbook workBook;

	protected Sheet workSheet;

	protected Row rows;

	protected Cell cell;

	protected LinkedList<Color[]> colorRecords = null;

	protected Long maximumRows = 0L;

	protected int numSheet;

	/**
	 * Color paletter adalah local instance untuk satu workbook.
	 */
	protected ExcelColor color;

	public AbstractExcel(String excelExtension) {
		workBook = new HSSFWorkbook();
		maximumRows = Excel.EXCEL_2003_MAX_ROWS;

		numSheet = 0;
		records = new LinkedList<Object[]>();
		createNewSheet();
	}

	/**
	 * Tambah warna record untuk tabel.
	 * 
	 * @param colorRecord
	 *            warna-warna record
	 */
	public void addColorRecord(Color[] colorRecord) {
		if (colorRecords == null) {
			colorRecords = new LinkedList<Color[]>();
		}

		colorRecords.add(colorRecord);
	}

	/**
	 * Buat header tabel.
	 */
	protected void createHeader() {
		CellStyle styleHeader = createStyleHeader();

		// Cell untuk nomor
		// createStringCell(0, styleHeader, "NO.");

		// Isi nama kolom header.
		for (int i = 0; i < headers.length; i++) {
			createStringCell(i, styleHeader, headers[i].getName());
		}
	}

	/**
	 * Membuat sheet baru.
	 * 
	 * @param nameSheet
	 *            - nama sheet
	 */
	protected void createNewSheet() {
		numSheet++;
		workSheet = workBook.createSheet("Sheet " + numSheet);
		rows = workSheet.createRow(0);
	}

	/**
	 * Membuat default style untuk cell.
	 * 
	 * @param styleBorder
	 *            border style
	 * @return cell style
	 */
	protected CellStyle createDefaultStyle(short styleBorder) {
		CellStyle style = workBook.createCellStyle();

		style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
		style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
		style.setRightBorderColor(IndexedColors.BLACK.getIndex());
		style.setTopBorderColor(IndexedColors.BLACK.getIndex());

		style.setBorderBottom(styleBorder);
		style.setBorderLeft(styleBorder);
		style.setBorderRight(styleBorder);
		style.setBorderTop(styleBorder);
		style.setAlignment(CellStyle.VERTICAL_TOP);

		return style;
	}

	/**
	 * Cek apakah sheet telah melebihi batas baris.
	 */
	protected void checkSheetLimitation() {
		if (rows.getRowNum() == maximumRows) {
			/**
			 * Buat sheet baru.
			 */
			createNewSheet();
			createHeader();
		}
	}

	/**
	 * Sesuaikan ukuran kolom, sehingga dapat terlihat semua isi cell-nya.
	 */
	protected void resizeWorkSheet() {
		for (int i = 0; i <= headers.length; i++) {
			workSheet.autoSizeColumn(i);
		}
	}

	/**
	 * Membuat cell style untuk badan tabel.
	 * 
	 * @return cell style
	 */
	protected CellStyle createStyleTableBody() {
		return createDefaultStyle(CellStyle.BORDER_THIN);
	}

	/**
	 * Mendapatkan style cell berdasarkan field-nya.
	 * 
	 * @param rowIdx
	 *            indeks baris
	 * @param colIdx
	 *            indeks kolom
	 * @return style cell
	 */
	protected CellStyle getStyleCell(int rowIdx, int colIdx) {
		if (colorRecords != null) {
			Color color = colorRecords.get(rowIdx)[colIdx];
			if (color != null) {
				short colorIdx = getColor(color.getRGB());
				CellStyle styleCell = createStyleTableBody();
				styleCell.setFillForegroundColor(colorIdx);
				styleCell.setFillPattern(CellStyle.SOLID_FOREGROUND);
				return styleCell;
			}
		}
		return createStyleTableBody();
	}

	/**
	 * Ambil warna yang sesuai.
	 * 
	 * @param rgb
	 *            kombinasi warna
	 * @return index warna di excel
	 */
	private short getColor(RGB rgb) {
		if (color == null) {
			color = new ExcelColor(((HSSFWorkbook) workBook).getCustomPalette());
		}
		return color.getIndex(rgb);
	}

	/**
	 * Membuat style untuk table header.
	 * 
	 * @return style cell
	 */
	protected CellStyle createStyleHeader() {
		CellStyle style = createDefaultStyle(CellStyle.BORDER_MEDIUM);
		// buat font.
		Font font = workBook.createFont();
		font.setFontHeightInPoints((short) 12);
		font.setFontName(Excel.FONT_ARIAL);
		font.setBoldweight((short) 2);
		style.setFont(font);
		return style;
	}

	/**
	 * Inisialisasi cell.
	 * 
	 * @param columnIndex
	 *            indeks kolom
	 * @param cellStyle
	 *            style cell
	 */
	private void initCell(int columnIndex, CellStyle cellStyle) {
		cell = rows.createCell(columnIndex);
		if (cellStyle != null) {
			cell.setCellStyle(cellStyle);
		}
	}

	/**
	 * Buat cell untuk tipe float.
	 * 
	 * @param columnIndex
	 *            indeks kolom
	 * @param cellStyle
	 *            style cell
	 * @param text
	 *            nilai/isi
	 */
	protected void createStringCell(int columnIndex, CellStyle cellStyle,
			String text) {
		initCell(columnIndex, cellStyle);
		cell.setCellValue(text);
	}

	/**
	 * Buat cell untuk tipe float.
	 * 
	 * @param columnIndex
	 *            indeks kolom
	 * @param cellStyle
	 *            style cell
	 * @param value
	 *            nilai/isi
	 */
	protected void createIntegerCell(int columnIndex, CellStyle cellStyle,
			Integer value) {
		initCell(columnIndex, cellStyle);
		cell.setCellValue((int) value);
	}

	/**
	 * Buat cell untuk tipe float.
	 * 
	 * @param columnIndex
	 *            indeks kolom
	 * @param cellStyle
	 *            style cell
	 * @param value
	 *            nilai/isi
	 */
	protected void createFloatCell(int columnIndex, CellStyle cellStyle,
			Float value) {
		initCell(columnIndex, cellStyle);
		cell.setCellValue((float) value);
	}

	/**
	 * Membuat blank cell.
	 * 
	 * @param columnIndex
	 *            indeks kolom
	 * @param cellStyle
	 *            style dari cell
	 */
	protected void createBlankCell(int columnIndex, CellStyle cellStyle) {
		initCell(columnIndex, cellStyle);
		cell.setCellType(Cell.CELL_TYPE_BLANK);
	}

	@Override
	public void writeTo(OutputStream outputStream) throws IOException {
		workBook.write(outputStream);
	}
}
